package com.hatricks.is.base.date;

import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashSet;
import java.util.Set;

/**
 * @packageName: com.chinasoft.broker.commons.utils.dateutils
 * @className: WorkDayComputeUtils
 * @author: yanyuhui yanyuhui@chinasofti.com
 * @date: 2022/1/20 19:38
 * @description: 工作日计算工具类
 * <p>
 * 22年数据来自于国务院官方数据
 * ** 目前仅支持22年当前的日期计算方式,如若传入的数据不在当年范围之内,可以正常偏移但是不计算具体工作日
 */
public class WorkDayComputeUtils {

    // format  yyyy-MM-dd   总共115条数据
    private static final Set<DateTime> DAY_CONTAINER = new HashSet<>();
    private static final String DATE_FORMAT = "yyyy/MM/dd";

    public static boolean isOverTime(LocalDateTime startTime, LocalDateTime endTime, Integer standardDay) {
        Assert.notNull(startTime, "开始时间不能为空");
        Assert.notNull(endTime, "结束时间不能为空");
        Assert.notNull(standardDay, "标准时间");
        // 标准结束时间
        LocalDateTime standardEndTime = getWorkDayOffset(startTime, standardDay);
        // 标准时间大于结束时间,则未超时 大于0 大于
        return CompareUtil.compare(standardEndTime, endTime) < 0;
    }

    /**
     * 传入LocalDateTime时间和偏移量
     *
     * @param dateTime 时间
     * @param offset   偏移量  如果当前偏移量不传,默认为1,如果offset为负,则往前计算
     * @return 返回偏移之后的时间
     */
    public static LocalDateTime getWorkDayOffset(LocalDateTime dateTime, Integer offset) {
        Assert.notNull(dateTime, "起始时间不能为空");
        offset = offset == null ? 1 : offset;
        DateTime computeDateTime = DateUtil.parse(dateTime.format(DateTimeFormatter.ofPattern(DATE_FORMAT)), DateTimeFormatter.ofPattern(DATE_FORMAT));
        if (offset >= 0) {
            int begin = 1;
            while (begin <= offset) {
                computeDateTime = DateUtil.offsetDay(computeDateTime, 1);
                while (DAY_CONTAINER.contains(computeDateTime)) {
                    // 当前偏移量包含休息日的情况下,继续偏移
                    computeDateTime = DateUtil.offsetDay(computeDateTime, 1);
                }
                begin++;
            }
            LocalDate localDate = computeDateTime.toLocalDateTime().toLocalDate();
            return LocalDateTime.of(localDate, dateTime.toLocalTime());
        } else {
            while (offset <= 0) {
                computeDateTime = DateUtil.offsetDay(computeDateTime, -1);
                // 当前偏移量包含休息日的情况下,继续偏移
                while (DAY_CONTAINER.contains(computeDateTime)) {
                    computeDateTime = DateUtil.offsetDay(computeDateTime, -1);
                }
                offset++;
            }
            LocalDate localDate = computeDateTime.toLocalDateTime().toLocalDate();
            return LocalDateTime.of(localDate, dateTime.toLocalTime());
        }
    }


    /**
     * 传入时间,自动计算当前时间是否是休息日,如果是休息日就自动加1,如果不是,则返回当前时间
     *
     * @param dateTime 当前时间
     * @return 计算之后的时间
     */
    public static LocalDateTime getWorkDay(LocalDateTime dateTime) {
        DateTime computeDateTime = DateUtil.parse(dateTime.format(DateTimeFormatter.ofPattern(DATE_FORMAT)), DateTimeFormatter.ofPattern(DATE_FORMAT));
        while (DAY_CONTAINER.contains(computeDateTime)) {
            // 当前偏移量包含休息日的情况下,继续偏移
            computeDateTime = DateUtil.offsetDay(computeDateTime, 1);
        }
        LocalDate localDate = computeDateTime.toLocalDateTime().toLocalDate();
        return LocalDateTime.of(localDate, dateTime.toLocalTime());
    }

    /**
     * 基于当前时间之后的偏移量
     *
     * @param offset 偏移位置,不传默认为1
     * @return 偏移之后的日期
     */
    public static LocalDateTime getWorkDayOffset(Integer offset) {
        return getWorkDayOffset(LocalDateTime.now(), offset);
    }

    static {
        /*1月份休息日*/
        DAY_CONTAINER.add(DateTime.of("2022/01/01 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/01/02 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/01/03 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/01/08 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/01/09 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/01/15 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/01/16 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/01/22 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/01/23 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/01/31 00:00:00", DATE_FORMAT));
        /*2月份休息日*/
        DAY_CONTAINER.add(DateTime.of("2022/02/01 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/02/02 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/02/03 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/02/04 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/02/05 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/02/06 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/02/12 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/02/13 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/02/19 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/02/20 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/02/26 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/02/27 00:00:00", DATE_FORMAT));
        /*3月份休息日*/
        DAY_CONTAINER.add(DateTime.of("2022/03/05 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/03/06 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/03/12 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/03/13 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/03/19 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/03/20 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/03/26 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/03/27 00:00:00", DATE_FORMAT));
        /*4月份休息日*/
        DAY_CONTAINER.add(DateTime.of("2022/04/03 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/04/04 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/04/05 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/04/09 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/04/10 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/04/16 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/04/17 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/04/23 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/04/30 00:00:00", DATE_FORMAT));
        /*5月份休息日*/
        DAY_CONTAINER.add(DateTime.of("2022/05/01 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/05/02 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/05/03 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/05/04 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/05/08 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/05/14 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/05/15 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/05/21 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/05/22 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/05/28 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/05/29 00:00:00", DATE_FORMAT));
        /*6月份休息日*/
        DAY_CONTAINER.add(DateTime.of("2022/06/03 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/06/04 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/06/05 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/06/11 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/06/12 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/06/18 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/06/19 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/06/25 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/06/26 00:00:00", DATE_FORMAT));
        /*7月份休息日*/
        DAY_CONTAINER.add(DateTime.of("2022/07/02 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/07/03 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/07/09 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/07/10 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/07/16 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/07/17 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/07/23 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/07/24 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/07/30 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/07/31 00:00:00", DATE_FORMAT));
        /*8月份休息日*/
        DAY_CONTAINER.add(DateTime.of("2022/08/06 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/08/07 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/08/13 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/08/14 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/08/20 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/08/21 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/08/27 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/08/28 00:00:00", DATE_FORMAT));
        /*9月份休息日*/
        DAY_CONTAINER.add(DateTime.of("2022/09/03 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/09/04 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/09/10 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/09/11 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/09/12 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/09/17 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/09/18 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/09/24 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/09/25 00:00:00", DATE_FORMAT));
        /*10月份休息日*/
        DAY_CONTAINER.add(DateTime.of("2022/10/01 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/10/02 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/10/03 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/10/04 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/10/05 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/10/06 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/10/07 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/10/15 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/10/16 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/10/22 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/10/23 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/10/29 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/10/30 00:00:00", DATE_FORMAT));
        /*11月份休息日*/
        DAY_CONTAINER.add(DateTime.of("2022/11/05 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/11/06 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/11/12 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/11/13 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/11/19 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/11/20 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/11/26 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/11/27 00:00:00", DATE_FORMAT));
        /*12月份休息日*/
        DAY_CONTAINER.add(DateTime.of("2022/12/03 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/12/04 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/12/10 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/12/11 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/12/17 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/12/18 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/12/24 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/12/25 00:00:00", DATE_FORMAT));
        DAY_CONTAINER.add(DateTime.of("2022/12/31 00:00:00", DATE_FORMAT));
    }

}
